package com.example.diagnostic;

import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Method;
import java.util.Iterator;
import java.util.Set;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.Vibrator;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

public class DiagnosticsActivity extends Activity {
	
    /*******************************************************
     * Variable Initialization
     ******************************************************/
	
	// Error Definitions
	
	private final static int OK = 0;
	private final static int BAD_DATA = -1;
	private final static int UNSUCCESSFUL = -2;
	private final static int IOERROR = -3;
	
	// Button Definitions
	
	private final static int INVISIBLE = 4;
	private final static int VISIBLE = 0;
	
	// State Definitions
	
	private final static int NOT_INITIALIZED = 0;
	private final static int INITIALIZED = 1;
	private final static int PREVIOUSLY_INITIALIZED = 2;
	private final static int CONNECTED = 3;
	private final static int COMMUNICATING = 4;
	
	// UI Handler

	private uHandler updateHandler = new uHandler();
   
    // UI Variables
    
	private TextView connection;
	private TextView rpm;
	private TextView mph;
	private Button bBluetooth_On;
	private Button bBluetooth_Off;
    
    // Function Flags
    
	private boolean stop = false;
	private boolean off_clickable = false;
	private boolean on_clickable = false;
	private boolean debugging = true;
	
    private int connection_state = NOT_INITIALIZED;
    private CommunicationManager cManager = new CommunicationManager();
    
    /*******************************************************
     * Broadcast Receivers
     ******************************************************/
/*
 * Broadcast Receivers: Used in this application to monitor connections and the state of bluetooth
 */
    
	public BroadcastReceiver btreceiver = new BroadcastReceiver(){
		
    	@Override
    	public void onReceive(Context context, Intent intent){
    		
    		/*
    		 * Purpose: Creates an interupt when Bluetooth changes states.
    		 			
    		 * Input: 	context - The interface that the application lies within
    		 * 			intent - What android is trying to do
    		 * Output: 	Nothing
    		 */
    		
    		if(debugging) log("BR Bluetooth");
    		int bluetooth_state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR);
    		switch(bluetooth_state){
    			case BluetoothAdapter.STATE_OFF:
    				//Bluetooth is officially off
    				bBluetooth_On.setVisibility(VISIBLE);
    				on_clickable = true; // Allow user to click on button
    				break;
    			case BluetoothAdapter.STATE_ON:
    				//Bluetooth is officially on
    				int error = cManager.initialize_bluetooth(); // Try to establish connection with paired device
    				bBluetooth_Off.setVisibility(VISIBLE);	
    				off_clickable = true; // Allow user to click off button
    				
    				if(error != OK){	// Wasn't able to connect
    					connection_state = PREVIOUSLY_INITIALIZED;
    					print_msg(context, "Error Connecting Via Bluetooth!");
    				}
    				else{
    					connection_state = INITIALIZED;	// Can connect waiting for the connection interrupt
    				}	
    				break;
    			case BluetoothAdapter.STATE_TURNING_ON:
    				// On Button has just been pressed
    				bBluetooth_On.setVisibility(INVISIBLE);
    				break;
    			case BluetoothAdapter.STATE_TURNING_OFF:
    				// Off button has just been pressed
    				connection_state = NOT_INITIALIZED;
    				cManager.close(); // Close all of the communication items
    				bBluetooth_Off.setVisibility(INVISIBLE);
    				break;
    			case BluetoothAdapter.ERROR:
    				// If none of the above there has been an error restart bluetooth
    				cManager.close();
    				cManager.bluetooth_off();
    				break;
    		}
    	};
    };
    
    public BroadcastReceiver monitor_connection_lost= new BroadcastReceiver(){
    	@Override
    	public void onReceive(Context context, Intent intent){
    		
    		/*
    		 * Purpose: Creates an interupt when the connection is lost.
    		 * 			Starts the closing of protocols so the phone doesn't crash
    		 * Input: 	context - The interface that the application lies within
    		 * 			intent - What android is trying to do
    		 * Output: 	Nothing
    		 */
    		
    		if(debugging) log("BR Connection Lost");
    		try{
				if(intent.getAction().equals("android.bluetooth.device.action.ACL_DISCONNECTED")){
					print_msg(context, "Connection Lost From Device");
					connection_state = NOT_INITIALIZED;
					cManager.close();
				}
    		}
			catch(Exception e){
				log("Error - BR Connection Lost: " + e.getLocalizedMessage());
			}
    	};
    };
    
    public BroadcastReceiver monitor_connection_connected = new BroadcastReceiver(){
    	@Override
    	public void onReceive(Context context, Intent intent){
    		
    		/*
    		 * Purpose: Creates an interupt when connection is made
    		 			Starts the set-up process of an established connection
    		 * Input: 	context - The interface that the application lies within
    		 * 			intent - What android is trying to do
    		 * Output: 	Nothing
    		 */
    		
    		if(debugging) log("BR Connection Made");
    		try{
    			if(intent.getAction().equals("android.bluetooth.device.action.ACL_CONNECTED")){
    				if(connection_state == INITIALIZED){
    					int error = cManager.initialize_communication();
    					if(error == OK){
    						connection_state = CONNECTED;
    					}
    					else{
    						print_msg(context, "Error in connecting, please restart phone and try again");
    					}
    				}
    				else{
    					print_msg(context, "Must Restart Bluetooth To Reconnect");
    				}
    			}		
    		}
    		catch(Exception e){
    			log("Error - BR Connection Made: " + e.getLocalizedMessage()); 
    		}
    	};
    };
    
    // Creates thread for updating GUI    
    
    class uHandler extends Handler {
        /* Purpose: Create a thread that can update the UI */
    
    	@Override
    	public void handleMessage(Message msg) {
       
         /* Purpose: Handler must handle a msg, when message received the handler updates the UI 
          * Input:   Message to the handler (arbitrary as only message this handler receives is from update 
          * Output:  Nothing
         */
       
    		DiagnosticsActivity.this.update();
    	}
    	
    	public void sleep(long delay){
         /* Purpose: Delays the sent message by a period of time allowing time so that the user can see the change 
          * Input:   Time in milliseconds to delay
          * Output:  Nothing 
         */
         
    		this.removeMessages(0); //Any old messages with id 0 remove them
    		sendMessageDelayed(obtainMessage(0), delay); 
    	}
    };
    
   
    
    /*******************************************************
     * Android Life Cycle Functions
     ******************************************************/
    
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    
         /* Purpose: ANDROID STATE - called when the application is created and starts taking resources
          * Input: State of the application previously
          * Output: None
          */
          
    	super.onCreate(savedInstanceState); 
		if(debugging) log("onCreate()");
    	
    	this.registerReceiver(btreceiver, new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED));
    	this.registerReceiver(monitor_connection_lost, new IntentFilter(BluetoothDevice.ACTION_ACL_DISCONNECTED));
    	this.registerReceiver(monitor_connection_connected, new IntentFilter(BluetoothDevice.ACTION_ACL_CONNECTED));

    	// Setup GUI
       
    	setContentView(R.layout.main); // Sets the layout using main.xml
    	
    	// Creates GUI
    	
		this.bBluetooth_On = (Button)findViewById(R.id.bluetooth_on);
		this.bBluetooth_Off = (Button)findViewById(R.id.bluetooth_off);
		
		// Makes both buttons initialially invisible
		
		bBluetooth_On.setVisibility(INVISIBLE);
		bBluetooth_Off.setVisibility(INVISIBLE);
		
		// Attaches variables in the activity to components of the GUI
		
		this.connection = (TextView)findViewById(R.id.connection);
		this.rpm = (TextView)findViewById(R.id.rpm); 
		this.mph = (TextView)findViewById(R.id.mph);
		
		// On Button Click Handler
		
		bBluetooth_On.setOnClickListener(new OnClickListener(){
			@Override
			public void onClick(View view) {
				if(on_clickable == false) return;
				Vibrator vib = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
				vib.vibrate(200);
				on_clickable = true;
				cManager.bluetooth_on();
				return;
			}
		});
		
		// Off Button Click Handler
		
		bBluetooth_Off.setOnClickListener(new OnClickListener(){
			@Override
			public void onClick(View view) {
				if(off_clickable == false) return;
				Vibrator vib = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
				vib.vibrate(200);
				off_clickable = false;
				cManager.bluetooth_off();
				return;
			}
		});
		update();
    }
    
    @Override
    protected void onStart(){
    	
    	/*
    	 * Purpose: ANDROID STATE - Called when an application is already running and wants to be used
    	 */
    	
    	super.onStart();
		if(debugging) log("onStart()");
    	
     	if (!cManager.hasAdapter()){
	       print_msg(this, "No Bluetooth on your Device. This application will not work on this device.");
	       cManager.close();
	       finish();
    	}
     	
     	// Turn on the button that is opposite of the current state
     	
    	else{
    		if(cManager.hasBluetoothOn()){
    			bBluetooth_Off.setVisibility(VISIBLE);
    			off_clickable = true;
    			print_msg(this, "Please Restart Bluetooth, Connection May Have Already Been Established");
    		}
    		else{
    			bBluetooth_On.setVisibility(VISIBLE);
    			on_clickable = true;
    		}
    	}	
    }
    
    @Override
    protected void onDestroy(){ 
    	
    	/*
    	 * Purpose: ANDROID STATE - Called when phone needs application's resources
    	 */
    	
    	super.onDestroy();
		
    	if(debugging) log("onDestroy");
    	try{ 
    		this.unregisterReceiver(btreceiver);
    		this.unregisterReceiver(monitor_connection_connected);
    		this.unregisterReceiver(monitor_connection_lost);
    		stop = true;
    		cManager.close();
    	}	
    	catch(Exception e){
    		log("Error - onDestroy: " + e.getLocalizedMessage());
    	}
    }
    
    private void update(){
        
	    /* Purpose: To update the data within the gui before the handler updates
	     * Inputs:  None, gets data from external functions 
	     * Output:  Nothing
	     */
    	if(connection_state == COMMUNICATING){
    		connection.setText("Connection: Communicating");
    		
    		// Printing MPH
    		
    		try{
    			int realmph = cManager.getmph();
    			if(realmph > 128 || realmph < 0) mph.setText("MPH: ERROR");
            	else mph.setText("MPH: " + realmph);
    			log("MPH: " + realmph);
    		}
    		catch(Exception e){
    			log("Error - update(): " + e.getLocalizedMessage());
    			mph.setText("MPH: Error");
    		}
    		
    		// Printing RPM
    		
    		try{
    			int realrpm = cManager.getrpm();
	        	if(realrpm > 16384 || realrpm < 0) rpm.setText("RPM: ERROR");
	        	else rpm.setText("RPM: " + realrpm);
    		}
    		catch(Exception e){
    			log("Error - update(): " + e.getLocalizedMessage());
    			rpm.setText("RPM: Error");
    		}
    		
    		cManager.acknowledge();// Sending an 'I'm still here' byte to Bluetooth Bee
    	}
    	else if(connection_state == CONNECTED){
    		connection.setText("Connection: Waiting for Device");
    		if(cManager.wait_for_connection()) connection_state = COMMUNICATING;
    	}
    	else{
    		mph.setText("MPH: No Data");
    		rpm.setText("RPM: No Data");
    		connection.setText("Connection: Not Connected");
    	}
    	if(stop){	//Stops this function when the program ends
    		return;
    	}
    	else{
    		updateHandler.sleep(100);
    	}	
    }
	    
	/*******************************************************
     * Bluetooth Functions
     ******************************************************/	
	
    /*private void bluetooth_off(){
    	   
	    /*
	     * Purpose: Turn Bluetooth Off
	     * Input: Nothing
	     * Output: Nothing	
	     
    	
		if(debugging) log("bluetooth_off()");
    	
		try{
			BTadapter.disable();
			connection_state = NOT_INITIALIZED;
		}
		catch(Exception e){
			log("Error - bluetooth_off: " + e.getLocalizedMessage());
		}
    }
    
    private void bluetooth_on(){
    
	    /*
	     * Purpose: Turn Bluetooth On
	     * Input: Nothing
	     * Output: Nothing
	     
    	
		if(debugging) log("bluetooth_on()");
    	
		try{
			BTadapter.enable();
		}
		catch(Exception e){
			log("Error - bluetooth_on(): " + e.getLocalizedMessage());
		}
    }
	
	/*******************************************************
     * Data Functions
     ******************************************************/
    
	private void print_msg(Context context, String msg){
	
		/*
		 * Purpose: Print messages to the user
		 * Input: 	Context - Location in the GUI
		 * 			msg 	- Message to be printed to the user
		 * Output: Nothing 	
		 */
		
	    	int duration = Toast.LENGTH_LONG;
	    	Toast toast = Toast.makeText(context, msg, duration);
	    	toast.show();
	}
	
	private void log(String str){
		
		/*
		 * Purpose: Log data for debugging purposes
		 * Input: String to be output to the debugging location
		 * Output: Outputs data into a log
		 */
		
		Log.e("$$$$$$$$$$", str);
	}
}

